package cn.chiship.sdk.framework.base;

import cn.chiship.sdk.cache.service.UserCacheService;
import cn.chiship.sdk.cache.vo.CacheOrganizationVo;
import cn.chiship.sdk.cache.vo.CacheRoleVo;
import cn.chiship.sdk.cache.vo.CacheTenantVo;
import cn.chiship.sdk.cache.vo.CacheUserVO;
import cn.chiship.sdk.core.annotation.Authorization;
import cn.chiship.sdk.core.annotation.NoParamsSign;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.enums.BaseResultEnum;
import cn.chiship.sdk.core.exception.custom.BusinessException;
import cn.chiship.sdk.core.id.SnowflakeIdUtil;
import cn.chiship.sdk.core.util.ClassUtil;
import cn.chiship.sdk.core.util.DateUtils;
import cn.chiship.sdk.core.util.http.ResponseUtil;
import cn.chiship.sdk.framework.pojo.dto.export.ExportDto;
import cn.chiship.sdk.framework.pojo.dto.export.ImportDto;
import cn.chiship.sdk.framework.pojo.vo.OptionUser;
import cn.chiship.sdk.framework.util.BindingResultUtil;
import cn.chiship.sdk.framework.util.OptionUserUtil;
import cn.chiship.sdk.framework.util.ServletUtil;
import cn.chiship.sdk.core.util.StringUtil;
import cn.chiship.sdk.framework.pojo.vo.PageVo;

import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;

/**
 * @author lijian
 */
public abstract class BaseController<Record, Example> {

    /**
     * 获取业务服务
     */
    public abstract BaseService<Record, Example> getService();

    @Autowired
    UserCacheService userCacheService;

    @ApiOperation(value = "根据指定字段校验数据是否存在")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "主键", dataTypeClass = String.class, paramType = "query"),
            @ApiImplicitParam(name = "field", value = "字段", required = true, dataTypeClass = String.class,
                    paramType = "query"),
            @ApiImplicitParam(name = "value", value = "值", required = true, dataTypeClass = String.class,
                    paramType = "query"),})
    @Authorization
    @GetMapping(value = "validateExistByField")
    public ResponseEntity<BaseResult> validateExistByField(
            @RequestParam(required = false, defaultValue = "", value = "id") String id,
            @RequestParam(value = "field") String field, @RequestParam(value = "value") String value) {
        return new ResponseEntity<>(getService().validateExistByField(id, field, value), HttpStatus.OK);
    }

    @ApiOperation(value = "【导出】指定格式(exportType:csv、xls、xlsx、json)的数据文件，支持异步导出(async=true)")
    @ApiImplicitParams({})
    @PostMapping(value = "exportData")
    @NoParamsSign
    public void exportData(@RequestBody @Valid ExportDto exportDto, HttpServletResponse response) throws Exception {
        if (Boolean.TRUE.equals(exportDto.getAsync())) {
            String taskId = DateUtils.dateTimeNow() + SnowflakeIdUtil.generateId();
            getService().asyncExportData(response, taskId, exportDto);
            ResponseUtil.writeJson(response, BaseResult.ok(taskId));
        } else {
            getService().exportData(response, exportDto);
        }
    }

    @ApiOperation(value = "【导出】根据任务ID获取异步导出任务实时进度")
    @ApiImplicitParams({})
    @PostMapping(value = "getExportProcessStatus")
    public void getExportProcessStatus(HttpServletResponse response, @RequestBody @Valid String taskId)
            throws Exception {
        getService().getExportProcessStatus(response, taskId);
    }

    @ApiOperation(value = "【导入】导入Excel")
    @ApiImplicitParams({})
    @PostMapping(value = "/importData")
    @NoParamsSign
    public ResponseEntity<BaseResult> importData(@RequestParam("file") MultipartFile multipartFile) throws IOException {
        if (multipartFile.isEmpty()) {
            return new ResponseEntity<>(BaseResult.error("上传失败，请选择文件"), HttpStatus.OK);
        }
        String taskId = DateUtils.dateTimeNow() + SnowflakeIdUtil.generateId();
        Map<String, Object> paramMap = ServletUtil.getParameterValues();
        Boolean fileSave = Boolean.valueOf(paramMap.get("fileSave").toString());
        paramMap.remove("fileSave");
        ImportDto importDto = new ImportDto(multipartFile.getOriginalFilename(), fileSave,
                multipartFile.getContentType(), getLoginUser(), paramMap);
        getService().asyncImportData(taskId, multipartFile.getInputStream(), importDto);
        return new ResponseEntity<>(BaseResult.ok(taskId), HttpStatus.OK);

    }

    @ApiOperation(value = "【导入】根据任务ID获取异步导入任务实时进度")
    @PostMapping("/getImportProcessStatus")
    @ApiImplicitParams({})
    @NoParamsSign
    public ResponseEntity<BaseResult> getImportProcessStatus(@RequestBody @Valid String taskId) {
        return new ResponseEntity<>(getService().getImportProcessStatus(taskId), HttpStatus.OK);
    }

    @ApiOperation(value = "根据主键获取数据")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键ID", required = true, dataTypeClass = String.class,
            paramType = "path")})
    @GetMapping(value = "getById/{id}")
    public ResponseEntity<BaseResult> getById(@PathVariable("id") String id) {
        return new ResponseEntity<>(BaseResult.ok(getService().selectByPrimaryKey(id)), HttpStatus.OK);
    }

    @ApiOperation(value = "根据主键获取详情数据")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键ID", required = true, dataTypeClass = String.class,
            paramType = "path")})
    @GetMapping(value = "getDetailsById/{id}")
    public ResponseEntity<BaseResult> getDetailsById(@PathVariable("id") String id) {
        return new ResponseEntity<>(getService().selectDetailsByPrimaryKey(id), HttpStatus.OK);
    }

    /**
     * 分页
     *
     * @param example 条件
     */
    public PageVo page(Example example) {
        PageVo pageVo = ServletUtil.getPageVo();
        return getService().selectPageByExample(pageVo, example);
    }

    /**
     * 列表
     *
     * @param example 条件
     * @return 结果
     */
    public List<Record> list(Example example) {
        return getService().selectByExample(example);
    }

    /**
     * 新增
     *
     * @param record 实体类
     * @return 结果
     */
    public BaseResult save(Record record) {
        ClassUtil.setFieldValue(record, "createdBy", OptionUserUtil.getCurrentOptionUser(getLoginUser()));
        ClassUtil.setFieldValue(record, "createdUserId", getUserId());
        ClassUtil.setFieldValue(record, "createdUserName", getLoginUser().getRealName());
        try {
            CacheOrganizationVo cacheOrganizationVo = getLoginUserOrg();
            ClassUtil.setFieldValue(record, "createdOrgId", cacheOrganizationVo.getId());
            ClassUtil.setFieldValue(record, "createdOrgName", cacheOrganizationVo.getName());
        } catch (Exception e) {
        }

        return getService().insertSelective(record);
    }

    /**
     * 修改
     *
     * @param record 实体
     * @return 结果
     */
    public BaseResult update(Object id, Record record) {
        if (StringUtil.isNull(id)) {
            return BaseResult.error(BaseResultEnum.BUSINESS_ERROR, "参数[id]不能为空");
        }
        ClassUtil.setFieldValue(record, "id", id);
        ClassUtil.setFieldValue(record, "modifyBy", OptionUserUtil.getCurrentOptionUser(getLoginUser()));
        return getService().updateByPrimaryKeySelective(record);
    }

    /**
     * 删除
     *
     * @param example 条件
     */
    public BaseResult remove(Example example) {
        return getService().deleteByExample(example);
    }

    public BaseResult validParams(BindingResult bindingResult) {
        return BindingResultUtil.format(bindingResult);
    }

    /**
     * 获取当前登陆用户主键
     */
    protected String getUserId() {
        return getLoginUser().getId();
    }

    /**
     * 获得当前登陆用户名
     */
    protected String getUserName() {
        return getLoginUser().getUsername();
    }

    /**
     * 获得当前登陆用户真实姓名
     */
    protected String getRealName() {
        return getLoginUser().getRealName();
    }

    /**
     * 判断是否包含指定角色
     *
     * @param role 角色
     */
    protected boolean hasRole(String role) {
        return hasRole(Collections.singletonList(role));
    }

    /**
     * 判断是否包含指定角色集合
     *
     * @param roles 角色集合
     */
    protected boolean hasRole(List<String> roles) {
        List<String> hasRoles = getRoles();
        return hasRoles.containsAll(roles);
    }

    /**
     * 获得当前登陆用户所属组织
     */
    protected String getOrganizationId() {
        CacheOrganizationVo cacheOrganizationVo = getLoginUser().getCacheOrganizationVo();
        if (StringUtil.isNull(cacheOrganizationVo)) {
            throw new BusinessException("当前登陆用户暂无绑定组织信息！");
        }
        return cacheOrganizationVo.getId();
    }

    /**
     * 获得当前登陆用户所属机构
     */
    protected CacheOrganizationVo getLoginUserOrg() {
        CacheOrganizationVo cacheOrganizationVo = getLoginUser().getCacheOrganizationVo();
        if (StringUtil.isNull(cacheOrganizationVo)) {
            throw new BusinessException("当前登陆用户暂无绑定组织信息！");
        }
        return cacheOrganizationVo;
    }

    /**
     * 获得当前登陆用户所属机构主键
     */
    protected String getLoginUserOrgId() {
        CacheOrganizationVo cacheOrganizationVo = getLoginUserOrg();
        return cacheOrganizationVo.getId();
    }

    protected List<String> getRoles() {
        List<CacheRoleVo> roleVos = getLoginUser().getCacheRoleVos();
        List<String> roles = new ArrayList<>();
        if (roleVos != null) {
            for (CacheRoleVo roleVo : roleVos) {
                roles.add(roleVo.getRoleCode());
            }
        }
        return roles;
    }

    /**
     * 获得当前等了用户
     */
    protected CacheUserVO getLoginUser() {
        CacheUserVO cacheUserVO = userCacheService.getUser();
        if (StringUtil.isNull(cacheUserVO)) {
            throw new BusinessException("无法获得当前登陆用户,请反馈至管理员");
        }
        return cacheUserVO;
    }

    /**
     * 获得当前操作用户，已经格式化好了的 可用作字段create_by,modified_by等字段的存储
     */
    protected String getCurrentOptionUser() {
        return OptionUserUtil.getCurrentOptionUser(getLoginUser());
    }

    /**
     * 根据相关字段的存储，还原成OptionUser操作类
     *
     * @param optionUserStr 操作用户字符串
     */
    protected OptionUser getCurrentOptionUser(String optionUserStr) {
        return OptionUserUtil.getCurrentOptionUser(optionUserStr);
    }

    /**
     * 判断是否是租户
     *
     * @return Boolean
     */
    protected Boolean judgeTenant() {
        CacheTenantVo tenantVo = getLoginUser().getCacheTenantVo();
        return ObjectUtils.isNotEmpty(tenantVo);
    }

    /**
     * 获取租户ID
     *
     * @return String
     */
    protected String getTenantId() {
        if (Boolean.TRUE.equals(judgeTenant())) {
            return getLoginUser().getCacheTenantVo().getId();
        }
        throw new BusinessException("当前登陆用户不属于任何租户，请先使用judgeTenant()判断是否租户");
    }

    protected ResponseEntity<BaseResult> responseEntity(BaseResult baseResult) {
        return responseEntity(baseResult, HttpStatus.OK);
    }

    protected ResponseEntity<BaseResult> responseEntity(BaseResult baseResult, HttpStatus httpStatus) {
        return new ResponseEntity<>(baseResult, httpStatus);
    }

}
